use charming::Chart;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::{collections::HashMap, fmt::Display};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DisplayCols {
    Default,
    Part(Vec<String>),
}

use crate::{
    page_conf::parameter::Parameter,
    prelude::Align,
    structs::{ColumnCells, ContextMenus, RowRange},
    utils::format_json_value,
};

use super::{ColumnCell, OrderItems, WhereCauses};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ReportDataRequset {
    pub rept_name: String,
    pub params: Vec<(String, String)>,
    pub where_causes: Option<WhereCauses>,
    pub orders: Option<OrderItems>,
    pub display_cols: DisplayCols,
    pub group_index: u8,
    pub drill_downs: Vec<(u8, Value)>,
    pub user_id: u32,
    pub perm_id: u32,
    pub page: u32,
    pub size: u16,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ReportDataResponse {
    pub data: Vec<Value>,
    pub total: u64,
}
impl ReportDataResponse {
    pub fn get_total(&self) -> u64 {
        self.total
    }
    pub fn get_data(&self) -> &Vec<Value> {
        &self.data
    }
}
impl Default for ReportDataResponse {
    fn default() -> Self {
        Self {
            data: Vec::new(),
            total: 0,
        }
    }
}
#[cfg(feature = "ssr")]
impl ReportDataResponse {
    pub fn new(data: Vec<Vec<Value>>, total: u64) -> Self {
        let data = data.into_iter().map(Value::from).collect();
        Self { data, total }
    }
    pub fn add_drill_down(&mut self, index: usize, drill_down: Vec<Vec<Value>>) {
        let index = index + 1;
        let drill_down: Vec<Value> = drill_down.into_iter().map(Value::from).collect();
        self.data.splice(index..index, drill_down);
    }
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DrillDownData {
    pub group_index: u8,
    pub by_col: String,
    pub by_value: Value,
    pub data: Vec<Vec<Value>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReportDefine {
    pub title: String,
    #[serde(default)]
    pub unique_columns: Vec<String>,
    pub unit: Unit,
    #[serde(default)]
    pub params: Vec<Parameter>,
    pub groups: Vec<ReportGroup>,
    pub columns: Vec<ColumnCell>,
    pub chart: Option<Chart>,
    pub context_menus: Option<ContextMenus>,
    pub special_rows: Option<SpecialRows>,
    pub series_source: Option<SeriesSource>,
    pub has_export_sheet_col: bool,
}
impl ReportDefine {
    pub fn get_group_show_cols(&self, group_idx: u8) -> Vec<&str> {
        let mut res_cols: Vec<&str> = Vec::new();
        for i in 0..=group_idx {
            let group = &self.groups[i as usize];
            for col in group.name_cols.iter() {
                res_cols.push(col.as_str());
            }
        }
        res_cols
    }
    pub fn get_group_not_show_cols(&self, group_idx: u8) -> Vec<&str> {
        let glen = self.groups.len();
        let sidx = group_idx as usize + 1;
        let mut res_cols: Vec<&str> = Vec::new();
        for i in sidx..glen {
            let group = &self.groups[i];
            for col in group.name_cols.iter() {
                res_cols.push(col.as_str());
            }
        }
        res_cols
    }
    pub fn get_group_col_name(&self, group_idx: u8) -> Option<&str> {
        self.groups.get(group_idx as usize).map(|g| g.by.as_str())
    }
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ReportGroup {
    //分组标题
    pub title: String,
    //分组关键字
    pub by: String,
    //名称字段
    pub name_cols: Vec<String>,
    //小计字段
    #[serde(default)]
    pub subtotal: Option<Subtotal>,
    //查看权限
    #[serde(default)]
    pub row_range: RowRange,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Subtotal {
    #[serde(default)]
    pub suffix: String,
    pub agg_cols: Vec<String>,
    pub agg_exps: HashMap<String, String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Unit {
    Yuan,
    WanYuan,
    YiYuan,
    Ge,
    Hu,
    Percent
}
impl Unit {
    pub fn to_u32(&self) -> u32 {
        match self {
            Unit::Yuan | Unit::Ge | Unit::Hu => 1,
            Unit::WanYuan => 10000,
            Unit::YiYuan => 100000000,
            Unit::Percent => 1,
        }
    }
}
impl Default for Unit {
    fn default() -> Self {
        Unit::WanYuan
    }
}
impl Display for Unit {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Unit::Yuan => write!(f, "元"),
            Unit::WanYuan => write!(f, "万元"),
            Unit::YiYuan => write!(f, "亿元"),
            Unit::Ge => write!(f, "个"),
            Unit::Hu => write!(f, "户"),
            Unit::Percent => write!(f, "%"),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuthFilter {
    pub filter_type: AuthFilterType,
    pub col_name: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
pub enum AuthFilterType {
    User,
    Dept1,
    Dept2,
}
impl Default for AuthFilterType {
    fn default() -> Self {
        AuthFilterType::User
    }
}
impl AuthFilter {
    pub fn to_where_cause(&self, range: RowRange, user_id: u32) -> String {
        match self.filter_type{
            AuthFilterType::User=>{
                match range {
                    RowRange::All => "".to_string(),
                    RowRange::DeptSuper => format!("{} in (select EMID from DICT_USER_DEPT where PDID=(select top 1 PDID from DICT_USER_DEPT where EMID={user_id}))",self.col_name.as_str()),
                    RowRange::DeptSelf => format!("{} in (select EMID from DICT_USER_DEPT where DPID=(select top 1 DPID from DICT_USER_DEPT where EMID={user_id}))",self.col_name.as_str()),
                    RowRange::OneSelf => format!("{}={}",self.col_name.as_str(),user_id),
                }
            }
            AuthFilterType::Dept2=>{
                match range {
                    RowRange::All => "".to_string(),
                    RowRange::DeptSuper => format!("{} in (select DPID from DICT_DEPT where PDID=(select top 1 PDID from DICT_USER_DEPT where EMID={user_id}))",self.col_name.as_str()),
                    RowRange::DeptSelf => format!("{} = (select top 1 DPID from DICT_USER_DEPT where EMID={user_id})",self.col_name.as_str()),
                    RowRange::OneSelf  => "1<>1".to_string(),
                }
            }
            AuthFilterType::Dept1=>{
                match range {
                    RowRange::All => "".to_string(),
                    RowRange::DeptSuper => format!("{} = (select top 1 PDID from DICT_USER_DEPT where EMID={user_id})",self.col_name.as_str()),
                    RowRange::DeptSelf| RowRange::OneSelf  => "1<>1".to_string(),
                }
            }
        }
    }
}
impl<'de> Deserialize<'de> for AuthFilterType {
    fn deserialize<D>(deserializer: D) -> std::result::Result<AuthFilterType, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_lowercase().as_str() {
            "user" => Ok(AuthFilterType::User),
            "dept1" => Ok(AuthFilterType::Dept1),
            "dept2" => Ok(AuthFilterType::Dept2),
            _ => Err(serde::de::Error::custom(format!(
                "未知的AuthFilterType:{s}"
            ))),
        }
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum SpecialRows {
    Single(SpecialRow),
    Multiple(Vec<SpecialRow>),
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct SpecialRow {
    pub conditions: HashMap<String, Vec<Value>>,
    pub col_range: ColRange,
    #[serde(default)]
    pub is_merge: bool,
    #[serde(default)]
    pub align: Option<Align>,
    #[serde(default)]
    pub value: Option<String>,
    #[serde(default)]
    pub format: Option<String>,
}
pub struct SpecialRowData {
    pub col_range: ColRange,
    pub align: Option<Align>,
    pub is_merge: bool,
    pub show_value: Value,
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
pub struct ColRange {
    pub start: u8,
    pub end: u8,
}
pub fn get_special_row_props(
    hc: &ColumnCells,
    row_data: Vec<Value>,
    special_rows: &SpecialRows,
) -> (Option<SpecialRowData>, Vec<Value>) {
    let not_show_indexs = hc.get_not_show_indexs();
    match special_rows {
        SpecialRows::Single(special_row) => {
            let (matched, show_value, row_data) =
                is_special_row(hc, row_data, special_row, &not_show_indexs);
            if matched {
                return (
                    Some(SpecialRowData {
                        col_range: special_row.col_range.clone(),
                        align: special_row.align,
                        is_merge: special_row.is_merge,
                        show_value,
                    }),
                    row_data,
                );
            }
            (None, row_data)
        }
        SpecialRows::Multiple(special_rows) => {
            let mut row_data2 = row_data;
            for srow in special_rows.iter() {
                let (matched, show_value, row_data) =
                    is_special_row(hc, row_data2, srow, &not_show_indexs);
                if matched {
                    return (
                        Some(SpecialRowData {
                            col_range: srow.col_range.clone(),
                            align: srow.align,
                            is_merge: srow.is_merge,
                            show_value,
                        }),
                        row_data,
                    );
                }
                row_data2 = row_data;
            }
            (None, row_data2)
        }
    }
}
fn is_special_row(
    hc: &ColumnCells,
    row_data: Vec<Value>,
    special_row: &SpecialRow,
    not_show_indexs: &[usize],
) -> (bool, Value, Vec<Value>) {
    let matched = special_row.conditions.iter().all(|(col, vals)| {
        let idx = hc.get_position(col);
        if let Some(idx) = idx {
            if let Some(cell) = row_data.get(idx) {
                vals.contains(cell)
            } else {
                false
            }
        } else {
            false
        }
    });
    if !matched {
        return (false, Value::Null, row_data);
    }
    let mut row_data2 = row_data;
    if let Some(fmt) = &special_row.format {
        let mut s = special_row.col_range.start as usize;
        let mut e = special_row.col_range.end as usize;
        let small_count = not_show_indexs.iter().filter(|&&i| i < s).count();
        s = s + small_count;
        e = e + small_count;
        let skip_idxs = not_show_indexs
            .iter()
            .filter(|&&i| i >= s && i <= e)
            .cloned()
            .collect::<Vec<_>>();
        e = e + skip_idxs.len();
        for i in s..=e {
            if skip_idxs.contains(&i) {
                continue;
            }
            if let Some(v) = row_data2.get_mut(i) {
                if let Some(leaf) = hc.get_leaf_cell_by_idx(i) {
                    let val = format_json_value(Some(&leaf.data_type), Some(fmt), v);
                    *v = Value::String(val);
                }
            }
        }
    }
    let conf_val = &special_row.value;
    if conf_val.is_none() {
        return (true, Value::Null, row_data2);
    }
    let conf_val = conf_val.as_deref().unwrap();
    if conf_val.starts_with("{") && conf_val.ends_with("}") {
        let col_name = &conf_val[1..conf_val.len() - 1];
        let idx = hc.get_position(col_name);
        let show_value = if let Some(idx) = idx {
            let v = row_data2.get(idx);
            v.cloned().unwrap_or(Value::Null)
        } else {
            Value::Null
        };
        return (true, show_value, row_data2);
    }
    (matched, Value::from(conf_val), row_data2)
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SeriesSource {
    #[serde(default)]
    pub time_type: TimeType,
    //名称列
    pub name_column: String,
    //X轴列
    pub x_column: String,
    //Y轴列
    pub y_column: String,
    //显示周期
    #[serde(default = "show_period_default")]
    pub show_period: u32,
    //预测周期
    pub forecast_period: Option<u32>,
    //值格式化
    #[serde(default)]
    pub precision: u8,
    //默认选中系列名称
    #[serde(default)]
    pub first_name: Option<String>,
}
fn show_period_default() -> u32 {
    12
}
#[derive(Debug, Clone, PartialEq, Eq, Copy, Serialize)]
pub enum TimeType {
    Day,
    Month,
    Quarter,
    Year,
    None,
}
impl Default for TimeType {
    fn default() -> Self {
        TimeType::None
    }
}
impl<'de> Deserialize<'de> for TimeType {
    fn deserialize<D>(deserializer: D) -> std::result::Result<TimeType, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        match s.to_lowercase().as_str() {
            "day" => Ok(TimeType::Day),
            "month" => Ok(TimeType::Month),
            "quarter" => Ok(TimeType::Quarter),
            "year" => Ok(TimeType::Year),
            "none" | "" => Ok(TimeType::None),
            _ => Err(serde::de::Error::custom(format!("未知的TimeType:{s}"))),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ParamSelected {
    #[serde(default)]
    pub multiple: bool,
    #[serde(default)]
    pub default_values: DefaultSelected,
    #[serde(default = "grid_default")]
    pub grid: u8,
}
fn grid_default() -> u8 {
    3
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DefaultSelected {
    Single(String),
    Multiple(Vec<String>),
    None,
}
impl Default for DefaultSelected {
    fn default() -> Self {
        DefaultSelected::None
    }
}
